﻿
namespace TFSChangeLog.Operations.Services
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Documents;
    using System.Windows.Threading;
    using Microsoft.TeamFoundation.Client;
    using Microsoft.TeamFoundation.VersionControl.Client;
    using Microsoft.TeamFoundation.VersionControl.Common;
    using Novacode;
    using TFSChangeLog.ViewModel;
    using TFSChangeLog.DataAccess;

    /// <summary>
    /// Type of changes
    /// </summary>
    public enum ChangeTypeFlags
    {
        /// <summary>
        /// None change type
        /// </summary>
        None,

        /// <summary>
        /// Add change type
        /// </summary>
        Add,

        /// <summary>
        /// Delete change type
        /// </summary>
        Delete,

        /// <summary>
        /// Edit change type
        /// </summary>
        Edit,

        /// <summary>
        /// Rename change type
        /// </summary>
        Rename,

        /// <summary>
        /// Undelete change type
        /// </summary>
        Undelete,

        /// <summary>
        /// Rename Edit change type
        /// </summary>
        RenameEdit,
    }

    /// <summary>
    /// Source Class for keeping the original Source info.
    /// </summary>
    public class Source
    {
        /// <summary>
        /// Default const.
        /// </summary>
        public Source()
        {
        }

        /// <summary>
        /// three argument const.
        /// </summary>
        /// <param name="origChange">orig.change</param>
        /// <param name="origName">orig.file name</param>
        /// <param name="fromChangeSet">from change set</param>
        public Source(ChangeTypeFlags origChange, string origName, int fromChangeSet)
        {
            this.OrigChange = origChange;
            this.OrigName = origName;
            this.FromChangeSet = fromChangeSet;
        }

        /// <summary>
        /// one argument const.
        /// </summary>
        /// <param name="origChange">orig.change</param>
        public Source(ChangeTypeFlags origChange)
        {
            this.OrigChange = origChange;
        }

        /// <summary>
        /// Original change type
        /// </summary>
        public ChangeTypeFlags OrigChange
        {
            get;
            set;
        }

        /// <summary>
        /// Original file name
        /// </summary>
        public string OrigName
        {
            get;
            set;
        }

        /// <summary>
        /// From change set.
        /// </summary>
        public int FromChangeSet
        {
            get;
            set;
        }
    }

    /// <summary>
    /// Container Class for keeping the changeset track
    /// </summary>
    public class ContainerClass
    {
        /// <summary>
        /// Default const.
        /// </summary>
        public ContainerClass()
        {

        }

        /// <summary>
        /// Default const.
        /// </summary>
        /// <param name="origChange">orig. change</param>
        /// <param name="lastChange">last change</param>
        /// <param name="origName">orig file name</param>
        /// <param name="lastName">Last Name</param>
        /// <param name="fromChangeSet">From change set</param>
        public ContainerClass(Source source, ChangeTypeFlags lastChange, string lastName)
        {
            this.SourceObj = source;
            this.LastChange = lastChange;
            this.LastName = lastName;
        }

        public Source SourceObj
        {
            get;
            set;
        }

        public ChangeTypeFlags LastChange
        {
            get;
            set;
        }

        public string LastName
        {
            get;
            set;
        }
    }

    /// <summary>Summary description for <see cref="GenerateXmlChangesService"/> class.</summary>
    public class GenerateXmlChangesService
    {
        /// <summary>
        /// Generate the config changes.
        /// </summary>
        /// <param name="singleIterationList">iteration list </param>
        /// <param name="m_ViewModel">view model</param>
        public static void DoWork(int[] singleIterationList, MainWindowViewModel m_ViewModel)
        {
            var loopOptions = new ParallelOptions();
            loopOptions.CancellationToken = m_ViewModel.progressDialogViewModel.TokenSource.Token;
            try
            {
                Parallel.ForEach(singleIterationList, loopOptions, t => GenerateXmlChanges(m_ViewModel));
            }
            catch (OperationCanceledException)
            {
                var ShowCancellationMessage = new System.Action(m_ViewModel.progressDialogViewModel.ShowCancellationMessage);
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, ShowCancellationMessage);
            }
            catch (Exception e)
            {
                var ShowCancellationMessage = new System.Action(m_ViewModel.progressDialogViewModel.ShowCancellationMessage);
                Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, ShowCancellationMessage);
            }
        }

        /// <summary>
        /// Generate the xml changes for given changeset.
        /// </summary>
        /// <param name="m_ViewModel">View model.</param>
        public static void GenerateXmlChanges(MainWindowViewModel m_ViewModel)
        {
            ProgressDialogViewModel viewModel = m_ViewModel.progressDialogViewModel;

            TFSChangeLog.DataAccess.TFSChangeLogStaticConfigs.ResetDateTimeOnOutputFileNames();

            if (TFSChangeLog.DataAccess.TFSChangeLogStaticConfigs.IsRunningFromCommandPrompt == false)
            {
                SetProgressBarMessage(viewModel);
            }

            if (m_ViewModel.SelectedFromChangeSet.FromChangesetID >= m_ViewModel.SelectedToChangeSet.ToChangesetID)
            {
                Console.WriteLine(
                                         "ERROR                  : Selected Value in 'Start From ChangeSet' ({0}) should be less then " +
                                         "'End To ChangeSet' ({1}).",
                                         m_ViewModel.SelectedFromChangeSet.FromChangesetID,
                                         m_ViewModel.SelectedToChangeSet.ToChangesetID);
            }
            else
            {
                TfsTeamProjectCollection tfs = TFSConnection.GetTFSConnection();
                VersionControlServer sourceControl = tfs.GetService<VersionControlServer>();
                var changesetList = sourceControl.QueryHistory(
                                                               m_ViewModel.TFSProjectSelectedBranchName,
                                                               VersionSpec.Latest,
                                                               0,
                                                               RecursionType.Full,
                                                               null,
                                                               new ChangesetVersionSpec(m_ViewModel.SelectedFromChangeSet.FromChangesetID),
                                                               new ChangesetVersionSpec(m_ViewModel.SelectedToChangeSet.ToChangesetID),
                                                               Int32.MaxValue,
                                                               true,
                                                               false,
                                                               false,
                                                               true).Cast<Changeset>();

                StreamWriter writer = new StreamWriter(DataAccess.TFSChangeLogStaticConfigs.TFSConfigChangesFileName);
                List<string> addedFileList = new List<string>();
                List<string> modifiedFileList = new List<string>();
                List<string> deletedFileList = new List<string>();
                string[] imgArray = { "png", "jpeg", "jpg", "bmp", "gif", "thm", "tif", "yuv", "psd" };
                string line = string.Empty;
                LineDiff lineDiff = new LineDiff();
                DocX document = DocX.Create(DataAccess.TFSChangeLogStaticConfigs.TFSOutputFileName);
                Novacode.Paragraph p = null;
                Dictionary<string, ContainerClass> ChangedElements = new Dictionary<string, ContainerClass>();
                ContainerClass outContainer = null;
                List<string> extensionList = m_ViewModel.FileExtension.Split(',').Select(s => s.Trim()).ToList();
                string[] fileExtension = null;

                try
                {
                    p = document.InsertParagraph();
                    p.AppendLine("-------------------------------------------------------------------------------------------------").Bold();
                    p.AppendLine("TFSServer : " + m_ViewModel.TFSServerName).Bold();
                    p.AppendLine("TFSProjectName : " + m_ViewModel.TFSProjectName).Bold();
                    p.AppendLine("TFSProjectBranchName : " + m_ViewModel.TFSProjectSelectedBranchName).Bold();
                    p.AppendLine("ReportDate : " + DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString()).Bold();
                    p.AppendLine("ReportProducedBy : " + m_ViewModel._currentUser.DisplayName).Bold();
                    p.AppendLine("FromChangeSet : " + m_ViewModel.SelectedFromChangeSet.FromChangesetID.ToString()).Bold();
                    p.AppendLine("ToChangeSet : " + m_ViewModel.SelectedToChangeSet.ToChangesetID.ToString()).Bold();
                    p.AppendLine("File Extensions : " + m_ViewModel.FileExtension).Bold();
                    p.AppendLine("-------------------------------------------------------------------------------------------------").Bold();

                    foreach (Changeset changeSet in changesetList)
                    {
                        if (m_ViewModel.progressDialogViewModel.TokenSource.Token.IsCancellationRequested)
                        {
                            return;
                        }

                        if (changeSet.Changes.Length == 0)
                        {
                            System.Console.WriteLine("No items!");
                            return;
                        }
                        ChangeTypeFlags changeType = ChangeTypeFlags.None;
                        Change[] changes = sourceControl.GetChangesForChangeset(changeSet.ChangesetId, false, Int32.MaxValue, null, null, true);
                        string origFileName = string.Empty;
                        int origChangeset;
                        ChangeTypeFlags origFlag;
                        Source sourceObj = null;
                        for (int i = 0; i < changes.Count(); i++)
                        {
                            Change change = changes[i];
                            fileExtension = change.Item.ServerItem.Split('.');

                            // We need to write only file difference & not the folders,the last index contains the file extension - check this & compare with the user input.
                            if (change.Item.ItemType == ItemType.File && (extensionList.Contains(fileExtension[fileExtension.Length - 1])) && !((change.ChangeType & ChangeType.SourceRename) > 0 && (change.ChangeType & ChangeType.Delete) > 0)
                                && !fileExtension.Contains("exe"))
                            {
                                // if item is not present in the dictionary, add it otherwise update it with the last change type.
                                // SourceRename is handled through rename, do not add those items in the dictionary.
                                if (!ChangedElements.TryGetValue(change.Item.ServerItem, out outContainer))
                                {
                                    changeType = setChangeType(change.ChangeType);
                                    if ((change.ChangeType & ChangeType.Rename) > 0)
                                    {
                                        //an item can be renamed multiple item among changesets, pick up the oldest name of the renamed item.
                                        var result = ChangedElements.Count > 0 ? ChangedElements.Where(d => d.Key == change.MergeSources.First().ServerItem).Select(k => k.Key) : null;
                                        if (result != null && result.Count() > 0)
                                        {
                                            origFileName = ChangedElements[result.First()].SourceObj.OrigName;
                                            origChangeset = ChangedElements[result.First()].SourceObj.FromChangeSet;
                                            origFlag = ChangedElements[result.First()].SourceObj.OrigChange;
                                            sourceObj = new Source(origFlag, origFileName, origChangeset);
                                            ChangedElements.Remove(change.MergeSources.First().ServerItem);
                                            ChangedElements.Add(change.Item.ServerItem, new ContainerClass(sourceObj, changeType, change.Item.ServerItem));
                                            continue;
                                        }
                                        else
                                        {
                                            outContainer = new ContainerClass(new Source(changeType, change.MergeSources.First().ServerItem, change.Item.ChangesetId), changeType, change.Item.ServerItem);
                                        }
                                    }
                                    else
                                    {
                                        // an item can be in the renamed item list, if yes then do not add those items in the list.
                                        var renamedItem = ChangedElements.Count > 0 ? ChangedElements.Where(d => d.Value.SourceObj.OrigName == change.Item.ServerItem &&
                                            (d.Value.LastChange == ChangeTypeFlags.Rename || d.Value.LastChange == ChangeTypeFlags.RenameEdit)) : null;

                                        if (renamedItem == null || renamedItem.Count() == 0)
                                        {
                                            outContainer = new ContainerClass(new Source(changeType, change.Item.ServerItem, change.Item.ChangesetId), changeType, change.Item.ServerItem);
                                        }
                                    }

                                    if (outContainer != null)
                                    {
                                        ChangedElements.Add(change.Item.ServerItem, outContainer);
                                    }
                                }
                                else
                                {
                                    outContainer.LastChange = setChangeType(change.ChangeType);
                                    ChangedElements[change.Item.ServerItem] = outContainer;
                                }
                            }
                        }
                    }

                    Item item = null;
                    fileExtension = null;
                    List<string> addedImageFileList = new List<string>();
                    List<string> deletedImageFileList = new List<string>();
                    List<string> ChangedImageFileList = new List<string>();
                    List<string> RenamedImageFileList = new List<string>();

                    foreach (KeyValuePair<string, ContainerClass> element in ChangedElements)
                    {
                        string serverItem = string.Empty;
                        serverItem = element.Key;
                        outContainer = element.Value;

                        if ((outContainer.SourceObj.OrigChange == ChangeTypeFlags.Add && outContainer.LastChange == ChangeTypeFlags.Add)
                            || (outContainer.SourceObj.OrigChange == ChangeTypeFlags.Add && outContainer.LastChange == ChangeTypeFlags.Rename)
                            || (outContainer.SourceObj.OrigChange == ChangeTypeFlags.Add && outContainer.LastChange == ChangeTypeFlags.Edit))
                        {
                            fileExtension = serverItem.Split('.');
                            p = document.InsertParagraph();

                            // add case.For image just write the image name & not the content.
                            if (imgArray.Contains(fileExtension[fileExtension.Length - 1]))
                            {
                                if (imgArray.Contains(fileExtension[fileExtension.Length - 1]))
                                {
                                    if (!addedImageFileList.Contains("New Content Files"))
                                    {
                                        addedImageFileList.Add("New Content Files");
                                        addedImageFileList.Add("Added:");
                                    }

                                    addedImageFileList.Add(serverItem.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty));
                                }
                            }
                            else
                            {
                                p.AppendLine("Added:");
                                p.AppendLine(serverItem.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty)).Bold();
                                item = sourceControl.GetItem(serverItem, new ChangesetVersionSpec(m_ViewModel.SelectedToChangeSet.ToChangesetID));
                                var stream = new StreamReader(item.DownloadFile(), Encoding.Default);
                                while (!stream.EndOfStream)
                                {
                                    line = stream.ReadLine();
                                    p.AppendLine(line);
                                }

                                p.AppendLine();
                            }

                        }
                        else if ((outContainer.SourceObj.OrigChange == ChangeTypeFlags.Edit && outContainer.LastChange == ChangeTypeFlags.Edit)
                            || (outContainer.SourceObj.OrigChange == ChangeTypeFlags.Delete && outContainer.LastChange == ChangeTypeFlags.Edit)
                            || (outContainer.SourceObj.OrigChange == ChangeTypeFlags.Edit && outContainer.LastChange == ChangeTypeFlags.Rename)
                             || (outContainer.SourceObj.OrigChange == ChangeTypeFlags.Rename && outContainer.LastChange == ChangeTypeFlags.Edit)
                            || (outContainer.SourceObj.OrigChange == ChangeTypeFlags.RenameEdit && outContainer.LastChange == ChangeTypeFlags.RenameEdit))
                        {
                            // edit case.

                            DiffOptions diffOptions = new DiffOptions();
                            diffOptions.SourceLabel = "Start File";
                            diffOptions.TargetLabel = "End File";
                            diffOptions.UseThirdPartyTool = false;
                            diffOptions.StreamWriter = writer;
                            diffOptions.OutputType = DiffOutputType.Unified;
                            diffOptions.ContextLines = 5;
                            IDiffItem origItem = null;
                            IDiffItem newItem = null;

                            origItem = new DiffItemVersionedFile(sourceControl, outContainer.SourceObj.OrigName,
                                                                                    new ChangesetVersionSpec(m_ViewModel.SelectedFromChangeSet.FromChangesetID));

                            newItem = new DiffItemVersionedFile(sourceControl, serverItem, new ChangesetVersionSpec(m_ViewModel.SelectedToChangeSet
                                                                                   .ToChangesetID));
                            fileExtension = serverItem.Split('.');

                            // For image just write the image name & not the content.
                            if (!imgArray.Contains(fileExtension[fileExtension.Length - 1]))
                            {
                                if (outContainer.LastChange == ChangeTypeFlags.RenameEdit || outContainer.LastChange == ChangeTypeFlags.Rename)
                                {
                                    writer.WriteLine("OldFileName" + outContainer.SourceObj.OrigName.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty));
                                    writer.WriteLine("NewFileName" + serverItem.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty));
                                }

                                Difference.DiffFiles(sourceControl, origItem, newItem, diffOptions, null, true);
                            }
                            else
                            {
                                if (outContainer.LastChange == ChangeTypeFlags.RenameEdit || outContainer.LastChange == ChangeTypeFlags.Rename)
                                {
                                    RenamedImageFileList.Add("Renamed");
                                    RenamedImageFileList.Add(outContainer.SourceObj.OrigName.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty));
                                    RenamedImageFileList.Add("To");
                                    RenamedImageFileList.Add(serverItem.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty));
                                }
                                else
                                {
                                    if (!ChangedImageFileList.Contains("Changed"))
                                    {
                                        ChangedImageFileList.Add("Changed");
                                    }

                                    ChangedImageFileList.Add(serverItem.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty));
                                }
                            }
                        }
                        else if ((outContainer.SourceObj.OrigChange == ChangeTypeFlags.Edit && outContainer.LastChange == ChangeTypeFlags.Delete) || outContainer.SourceObj.OrigChange == ChangeTypeFlags.Delete && outContainer.LastChange == ChangeTypeFlags.Delete)
                        {
                            // delete case.
                            if (!deletedImageFileList.Contains("Deleted:"))
                            {
                                deletedImageFileList.Add("Deleted:");
                            }

                            deletedImageFileList.Add(serverItem.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty));
                            deletedFileList.Add(serverItem);

                        }
                        else if (outContainer.SourceObj.OrigChange == ChangeTypeFlags.Rename && outContainer.LastChange == ChangeTypeFlags.Rename)
                        {
                            p = document.InsertParagraph();
                            p.AppendLine("Renamed:");
                            p.AppendLine(outContainer.SourceObj.OrigName.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty)).Bold();
                            p.AppendLine("To:");
                            p.AppendLine(serverItem.Replace(m_ViewModel.TFSProjectSelectedBranchName, string.Empty)).Bold();

                        }
                        else if ((outContainer.SourceObj.OrigChange == ChangeTypeFlags.Add && outContainer.LastChange == ChangeTypeFlags.Delete) || outContainer.SourceObj.OrigChange == ChangeTypeFlags.Delete && outContainer.LastChange == ChangeTypeFlags.Add)
                        {
                            // none case.
                            // do not require any action, will be removed in the check in.
                        }
                    }

                    writer.Close();
                    ProcessDiffOutput(ref document, m_ViewModel, addedImageFileList, deletedImageFileList, ChangedImageFileList, RenamedImageFileList);
                    document.Save();

                    if (TFSChangeLog.DataAccess.TFSChangeLogStaticConfigs.IsRunningInSilentMode == false)
                    {
                        if (MessageBox.Show("File changes Completed \n Do you want to open the file","Confirmation", MessageBoxButton.YesNo) == MessageBoxResult.Yes)
                        {
                            System.Diagnostics.Process.Start(DataAccess.TFSChangeLogStaticConfigs.TFSOutputFileName);
                        }
                    }
                }
                catch (Exception ex)
                {
                    m_ViewModel.progressDialogViewModel.TokenSource.Cancel();
                    writer.Close();
                    MessageBox.Show(ex.Message, "Error",
                            MessageBoxButton.OK,
                            MessageBoxImage.Error,
                            MessageBoxResult.OK);
                }
            }
        }

        /// <summary>
        /// process the diff output & write to a doc. file
        /// </summary>
        /// <param name="document">document object</param>
        /// <param name="m_ViewModel">View model</param>
        /// <param name="addedImageFileList">added image file list</param>
        /// <param name="deletedImageFileList">deleted image file list</param>
        /// <param name="ChangedImageFileList">Changed image file list</param>
        /// <param name="RenamedImageFileList">Renamed image file list</param>
        private static void ProcessDiffOutput(ref DocX document, MainWindowViewModel m_ViewModel, List<string> addedImageFileList, List<string> deletedImageFileList, List<string> ChangedImageFileList, List<string> RenamedImageFileList)
        {
            string line = string.Empty;
            string newLine = "\\ No newline at end of file";
            var p = document.InsertParagraph();
            foreach (string s in addedImageFileList)
            {
                p.AppendLine(s);
            }

            foreach (string s in deletedImageFileList)
            {
                p.AppendLine(s);
            }

            foreach (string s in ChangedImageFileList)
            {
                p.AppendLine(s);
            }

            foreach (string s in RenamedImageFileList)
            {
                p.AppendLine(s);
            }

            p.AppendLine();

            // we have got the output from the TFS API, Now Process the output & write in an another file.
            StreamReader reader = new StreamReader(DataAccess.TFSChangeLogStaticConfigs.TFSConfigChangesFileName);
            string fileName = string.Empty;
            line = string.Empty;
            List<LineDiff> removedLines = new List<LineDiff>();
            List<LineDiff> addedLines = new List<LineDiff>();
            List<string> oldFileNames = new List<string>();
            List<string> RenamedFileNames = new List<string>();
            bool itemAdded, isLineAdded, isLineRemoved, foundChange = false;
            string fileExt = string.Empty;
            string RenamedFileName = string.Empty;
            string oldFileName = string.Empty;
            char[] trimChars = { ' ', '-', '+' };
            line = reader.ReadLine();
            while (!reader.EndOfStream)
            {
            FileStart:
                if (line.StartsWith("OldFileName"))
                {
                    p.AppendLine("Renamed");
                    oldFileName = line.Replace("OldFileName", string.Empty);
                    oldFileNames.Add(oldFileName);
                    p.AppendLine(line.Replace("OldFileName", string.Empty)).Bold();
                    oldFileName = string.Empty;
                }
                else if (line.StartsWith("NewFileName"))
                {
                    RenamedFileName = line.Replace("NewFileName", string.Empty);
                    RenamedFileNames.Add(RenamedFileName);
                }
                else if (line.StartsWith("--- $"))
                {
                    p = document.InsertParagraph();
                    fileName = line.Replace("--- " + m_ViewModel.TFSProjectSelectedBranchName, string.Empty);
                    fileName = fileName.Remove(fileName.IndexOf(";"));
                    if (!oldFileNames.Contains(fileName) && !RenamedFileNames.Contains(fileName))
                    {
                        p.AppendLine(fileName).Bold();
                    }
                    var fileList = fileName.Split('.');
                    fileExt = fileList[fileList.Length - 1];
                }
                else if (line.StartsWith("@@") && line.EndsWith("@@"))
                {
                    line = reader.ReadLine();

                    // next file starting point.
                    while (!line.StartsWith("--- $"))
                    {
                        if (reader.EndOfStream)
                        {
                            break;
                        }

                        removedLines.Clear();
                        addedLines.Clear();
                        foundChange = false;
                        itemAdded = false;
                        isLineAdded = false;
                        isLineRemoved = false;
                        if (line.Equals(newLine) || line.Equals(" ") || line.Equals(string.Empty))
                        {
                            line = reader.ReadLine();
                            continue;
                        }

                        // read till end of tag.
                        while (line != null && (!((line.EndsWith("/>") && fileExt == "skin") || (fileExt == "css" && line.EndsWith("}")) || (line.TrimEnd(' ').TrimStart(' ').StartsWith("</") && line.TrimEnd(' ').EndsWith(">"))) || foundChange == false))
                        {
                            itemAdded = false;

                            if (line.StartsWith("--- $"))
                            {
                                if (isLineAdded || isLineRemoved)
                                {
                                    // There might be some change line which not have been written to the output file, write them before starting with the next changeset.
                                    writeChangedContent(removedLines, addedLines, isLineAdded, isLineRemoved, ref p);
                                }

                                removedLines.Clear();
                                addedLines.Clear();
                                foundChange = false;
                                itemAdded = false;
                                isLineAdded = false;
                                isLineRemoved = false;
                                goto FileStart;
                            }

                            if (line.StartsWith("-") && line.TrimStart(trimChars) != string.Empty)
                            {
                                removedLines.Add(new LineDiff(line, LineDiff.ChangedFlag.removed));
                                foundChange = true;
                                itemAdded = true;
                                isLineRemoved = true;
                            }

                            if (line.StartsWith("+") && line.TrimStart(trimChars) != string.Empty)
                            {
                                addedLines.Add(new LineDiff(line, LineDiff.ChangedFlag.added));
                                foundChange = true;
                                itemAdded = true;
                                isLineAdded = true;
                            }

                            // if we have not found the change & add the end tag is there, that means we have got the lines
                            // above the change, so remove those lines.
                            if (foundChange == false)
                            {
                                if (((line.EndsWith("/>") || line.EndsWith("--%>")) && fileExt == "skin") || ((line.StartsWith("</") && line.EndsWith(">")) || line.EndsWith("--%>")))
                                {
                                    removedLines.Clear();
                                    addedLines.Clear();
                                }
                            }

                            if (!itemAdded && !line.StartsWith("@@") && !line.StartsWith("===================") && line != newLine)
                            {
                                removedLines.Add(new LineDiff(line, LineDiff.ChangedFlag.original));
                                addedLines.Add(new LineDiff(line, LineDiff.ChangedFlag.original));
                            }

                            line = reader.ReadLine();
                            if (reader.EndOfStream)
                            {
                                break;
                            }
                        }

                        bool isLastLineChanged = false;

                        // this is a case where the last line i.e.end tag has been changed(For e.x. +    SkinID="SearchOptions.OptionsPage" />) & there are more changes after that.
                        if (line.StartsWith("-") && line.TrimStart(trimChars) != string.Empty && line != newLine)
                        {
                            removedLines.Add(new LineDiff(line, LineDiff.ChangedFlag.removed));
                            isLineRemoved = true;
                            isLastLineChanged = true;
                        }
                        else if (line.StartsWith("+") && line.TrimStart(trimChars) != string.Empty && line != newLine)
                        {
                            addedLines.Add(new LineDiff(line, LineDiff.ChangedFlag.added));
                            isLineAdded = true;
                            isLastLineChanged = true;
                        }

                        if (!reader.EndOfStream)
                        {
                            line = reader.ReadLine();

                            while (line.StartsWith("+"))
                            {
                                if (line.TrimStart(trimChars) == string.Empty || line == newLine)
                                {
                                    if (!reader.EndOfStream)
                                    {
                                        line = reader.ReadLine();
                                    }

                                    continue;
                                }

                                addedLines.Add(new LineDiff(line, LineDiff.ChangedFlag.added));
                                isLineAdded = true;
                                isLastLineChanged = true;
                                if (!reader.EndOfStream)
                                {
                                    line = reader.ReadLine();
                                }
                            }
                        }

                        if (isLineRemoved && isLineAdded)
                        {
                            p.AppendLine("Changed :");

                            foreach (LineDiff s in removedLines)
                            {
                                if (s.Flag == LineDiff.ChangedFlag.removed)
                                {
                                    p.AppendLine(s.Line.TrimStart(trimChars)).Color(Color.Red);
                                }
                                else
                                {
                                    p.AppendLine(s.Line.TrimStart(trimChars));
                                }
                            }

                            if (!isLastLineChanged)
                            {
                                p.AppendLine(line != newLine && !(line.StartsWith("@@") && line.EndsWith("@@")) && !line.StartsWith("===================") ? line.TrimStart(trimChars) : string.Empty);
                            }

                            p.AppendLine();

                            if (!string.IsNullOrEmpty(RenamedFileName))
                            {
                                p.AppendLine(RenamedFileName).Bold();
                                RenamedFileName = string.Empty;
                            }

                            p.AppendLine("To :");

                            foreach (LineDiff s in addedLines)
                            {
                                if (s.Flag == LineDiff.ChangedFlag.added)
                                {
                                    p.AppendLine(s.Line.TrimStart(trimChars)).Color(Color.Green);
                                }
                                else
                                {
                                    p.AppendLine(s.Line.TrimStart(trimChars));
                                }
                            }

                            if (!isLastLineChanged)
                            {
                                p.AppendLine(line != newLine && !(line.StartsWith("@@") && line.EndsWith("@@")) && !line.StartsWith("===================") ? line.TrimStart(trimChars) : string.Empty);
                            }

                            p.AppendLine();
                            addedLines.Clear();
                        }
                        else if (isLineRemoved && !isLineAdded)
                        {

                            if (!string.IsNullOrEmpty(RenamedFileName))
                            {
                                p.AppendLine(RenamedFileName).Bold();
                                RenamedFileName = string.Empty;
                            }

                            p.AppendLine("Removed :");
                            foreach (LineDiff s in removedLines)
                            {
                                if (s.Flag == LineDiff.ChangedFlag.removed)
                                {
                                    p.AppendLine(s.Line.TrimStart(trimChars)).Color(Color.Red);
                                }
                                else
                                {
                                    p.AppendLine(s.Line.TrimStart(trimChars));
                                }
                            }

                            if (!isLastLineChanged)
                            {
                                p.AppendLine(line != newLine && !(line.StartsWith("@@") && line.EndsWith("@@")) && !line.StartsWith("===================") ? line.TrimStart(trimChars) : string.Empty);
                            }

                            p.AppendLine();
                            removedLines.Clear();
                        }
                        else if (!isLineRemoved && isLineAdded)
                        {

                            if (!string.IsNullOrEmpty(RenamedFileName))
                            {
                                p.AppendLine(RenamedFileName).Bold();
                                RenamedFileName = string.Empty;
                            }

                            p.AppendLine("Added :");
                            foreach (LineDiff s in addedLines)
                            {
                                if (s.Flag == LineDiff.ChangedFlag.added)
                                {
                                    p.AppendLine(s.Line.TrimStart(trimChars)).Color(Color.Green);
                                }
                                else
                                {
                                    p.AppendLine(s.Line.TrimStart(trimChars));
                                }
                            }

                            if (!isLastLineChanged)
                            {
                                p.AppendLine(line != newLine && !(line.StartsWith("@@") && line.EndsWith("@@")) && !line.StartsWith("===================") ? line.TrimStart(trimChars) : string.Empty);
                            }

                            p.AppendLine();
                            addedLines.Clear();
                            removedLines.Clear();
                        }
                    }

                    break;
                }

                line = reader.ReadLine();
            }

            if (!string.IsNullOrEmpty(line) && line.StartsWith("NewFileName"))
            {
                p.AppendLine("To");
                p.AppendLine(line.Replace("NewFileName", string.Empty)).Bold();
            }

            reader.Close();
        }

        /// <summary>
        /// sets the change type flag.
        /// </summary>
        /// <param name="changeType">Change type enum</param>
        /// <returns></returns>
        private static ChangeTypeFlags setChangeType(ChangeType changeType)
        {

            if (((changeType & ChangeType.Add) > 0 && (changeType & ChangeType.Edit) > 0) || (changeType & ChangeType.Add) > 0)
            {
                return ChangeTypeFlags.Add;
            }
            else if ((changeType & ChangeType.Rename) > 0 && (changeType & ChangeType.Edit) > 0)
            {
                return ChangeTypeFlags.RenameEdit;
            }
            else if (((changeType & ChangeType.Edit) > 0 && (changeType & ChangeType.Delete) > 0) || (changeType & ChangeType.Edit) > 0)
            {
                return ChangeTypeFlags.Edit;
            }
            else if ((changeType & ChangeType.Rename) > 0)
            {
                return ChangeTypeFlags.Rename;
            }
            else if ((changeType & ChangeType.Delete) > 0)
            {
                return ChangeTypeFlags.Delete;
            }
            else if ((changeType & ChangeType.Undelete) > 0)
            {
                return ChangeTypeFlags.Undelete;
            }

            return ChangeTypeFlags.None;
        }

        /// <summary>
        /// Set Progress Bar Message.
        /// </summary>
        /// <param name="viewModel">TODO: Summary description for <c>viewModel</c> parameter of type <c>TFSChangeLog.ViewModel.ProgressDialogViewModel</c>.</param>
        private static void SetProgressBarMessage(ProgressDialogViewModel viewModel)
        {
            string message = "Generating File Changes ...";
            var SetProgressMessage = new Action<string>(viewModel.SetProgressMessage);
            Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, SetProgressMessage, message);
        }

        /// <summary>
        /// write the changed content to the file
        /// </summary>
        /// <param name="removedLines"> remove lines</param>
        /// <param name="addedLines">added lines </param>
        /// <param name="isLineAdded">This will be true if any line has been added</paraparam>
        /// <paparam name="isLineRemoved">This will be true if any line has been removed</paparam>
        private static void writeChangedContent(List<LineDiff> removedLines, List<LineDiff> addedLines, bool isLineAdded, bool isLineRemoved, ref Novacode.Paragraph p)
        {
            char[] trimChars = { ' ', '-', '+' };

            if (isLineRemoved && isLineAdded)
            {
                p.AppendLine("Changed :");

                foreach (LineDiff s in removedLines)
                {
                    if (s.Flag == LineDiff.ChangedFlag.removed)
                    {
                        p.AppendLine(s.Line.TrimStart(trimChars)).Color(Color.Red);
                    }
                    else
                    {
                        p.AppendLine(s.Line.TrimStart(trimChars));
                    }
                }

                p.AppendLine();
                p.AppendLine("To :");

                foreach (LineDiff s in addedLines)
                {
                    if (s.Flag == LineDiff.ChangedFlag.added)
                    {
                        p.AppendLine(s.Line.TrimStart(trimChars)).Color(Color.Green);
                    }
                    else
                    {
                        p.AppendLine(s.Line.TrimStart(trimChars));
                    }
                }

                p.AppendLine();
                addedLines.Clear();
            }
            else if (isLineRemoved && !isLineAdded)
            {
                p.AppendLine("Removed :");
                foreach (LineDiff s in removedLines)
                {
                    if (s.Flag == LineDiff.ChangedFlag.removed)
                    {
                        p.AppendLine(s.Line.TrimStart(trimChars)).Color(Color.Red);
                    }
                    else
                    {
                        p.AppendLine(s.Line.TrimStart(trimChars));
                    }
                }

                p.AppendLine();
                removedLines.Clear();
            }
            else if (!isLineRemoved && isLineAdded)
            {
                p.AppendLine("Added :");
                foreach (LineDiff s in addedLines)
                {
                    if (s.Flag == LineDiff.ChangedFlag.added)
                    {
                        p.AppendLine(s.Line.TrimStart(trimChars)).Color(Color.Green);
                    }
                    else
                    {
                        p.AppendLine(s.Line.TrimStart(trimChars));
                    }
                }

                p.AppendLine();
            }
        }
    }
}
